package com.wtpaint.lib.plugin.alipay;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;


import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import dalvik.system.DexClassLoader;

import static java.lang.Class.forName;

public final class PluginManager {

    private PackageInfo packageInfo;
    private Resources resources;
    private Context context;
    private DexClassLoader dexClassLoader;

    private static final PluginManager mInstance = new PluginManager();

    public static PluginManager getInstance() {
        return mInstance;
    }

    private PluginManager() {
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public PackageInfo getPackageInfo() {
        return packageInfo;
    }

    public Resources getResource() {
        return resources;
    }

    public DexClassLoader getDexClassLoader() {
        return dexClassLoader;
    }

    public void loadPath(Context context, String pathName) {
        File fileDir = context.getDir(Constants.FILE_PATH_PLUGIN, Context.MODE_PRIVATE);
        String path = new File(fileDir, pathName).getAbsolutePath();

        PackageManager packageManager = context.getPackageManager();
        packageInfo = packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);

        File dexOutFile = context.getDir("dex", Context.MODE_PRIVATE);

        dexClassLoader = new DexClassLoader(path, dexOutFile.getAbsolutePath(),
                null, context.getClassLoader());

        try {
            AssetManager assetManager = AssetManager.class.newInstance();

            Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
            addAssetPath.invoke(assetManager, path);
            resources = new Resources(assetManager, context.getResources().getDisplayMetrics(),
                    context.getResources().getConfiguration());

        } catch (Exception e) {
            e.printStackTrace();
        }
        parseReceivers(context, path);
    }

    @SuppressLint("PrivateApi")
    private void parseReceivers(Context context, String path) {

        try {

            Class packageParserClass = forName("android.content.pm.PackageParser");
            Method parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage", File.class, int.class);
            Object packageParser = packageParserClass.newInstance();
            Object packageObj = parsePackageMethod.invoke(packageParser, new File(path), PackageManager.GET_ACTIVITIES);
            Field receiverField = packageObj.getClass().getDeclaredField("receivers");
            List receivers = (List) receiverField.get(packageObj);
            Class<?> componentClass = forName("android.content.pm.PackageParser$Component");
            Field intentsField = componentClass.getDeclaredField("intents");
            Class<?> packageParser$ActivityClass = forName("android.content.pm.PackageParser$Activity");
            Class<?> packageUserStateClass = forName("android.content.pm.PackageUserState");
            Object defaultUserState = packageUserStateClass.newInstance();
            Method generateReceiverInfo = packageParserClass.getDeclaredMethod("generateActivityInfo",
                    packageParser$ActivityClass, int.class, packageUserStateClass, int.class);
            Class<?> userHandler = forName("android.os.UserHandle");
            Method getCallingUserIdMethod = userHandler.getDeclaredMethod("getCallingUserId");
            int userId = (int) getCallingUserIdMethod.invoke(null);

            for (Object activity : receivers) {
                ActivityInfo info = (ActivityInfo) generateReceiverInfo.invoke(packageParser, activity, 0, defaultUserState, userId);
                BroadcastReceiver broadcastReceiver = (BroadcastReceiver) dexClassLoader.loadClass(info.name).newInstance();
                List<? extends IntentFilter> intents = (List<? extends IntentFilter>) intentsField.get(activity);
                for (IntentFilter intentFilter : intents) {
                    context.registerReceiver(broadcastReceiver, intentFilter);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
